package core

import (
	"flag"
	"fmt"
	"github.com/fsnotify/fsnotify"
	"github.com/gin-gonic/gin"
	"github.com/spf13/viper"
	"go-backend-simple-scaffold/common/constants"
	"go-backend-simple-scaffold/global"
	"os"
)

// 配置文件优先级: 命令行 > 环境变量 > 默认值
func Viper(path ...string) *viper.Viper {
	var config string
	if len(path) == 0 {
		// 定义命令行参数 -c 指定配置文件
		flag.StringVar(&config, "c", "", "choose config file.")
		// 解析命令行参数
		flag.Parse()
		// 判断命令行参数是否为空
		if config == "" {
			// 判断constants.ConfigEnv环境变量是否为空
			if configEnv := os.Getenv(constants.ConfigEnv); configEnv == "" {
				switch gin.Mode() {
				case gin.DebugMode:
					config = constants.ConfigDefaultFile
					fmt.Printf("你正在使用gin模式的%s环境名称，config的路径为%s\n", gin.Mode(), constants.ConfigDefaultFile)
				case gin.ReleaseMode:
					config = constants.ConfigReleaseFile
					fmt.Printf("你正在使用gin模式的%s环境名称，config的路径为%s\n", gin.Mode(), constants.ConfigReleaseFile)
				case gin.TestMode:
					config = constants.ConfigTestFile
					fmt.Printf("你正在使用gin模式的%s环境名称，config的路径为%s\n", gin.Mode(), constants.ConfigTestFile)
				}
			} else {
				// constants.ConfigEnv 环境变量不为空，将值赋予config
				config = configEnv
				fmt.Printf("你正在使用%s环境变量，config的路径为%s\n", constants.ConfigEnv, config)
			}
		} else {
			// 命令行参数不为空，将值赋予config
			fmt.Printf("你正在使用命令行的-c参数传递值，config的路径为%s\n", config)
		}
	} else {
		// 函数传递的可变参数的第一个值赋予config
		config = path[0]
		fmt.Printf("你正在使用 func Viper()传递的值，config的路径为%s\n", config)
	}
	v := viper.New()
	v.SetConfigFile(config)
	v.SetConfigType("yaml")
	// 读取配置文件，将内容解析并存储在Viper实例中
	err := v.ReadInConfig()
	if err != nil {
		panic(fmt.Errorf("Fatal error config file: %s \n", err))
	}
	// 启动一个监听器，监听配置文件变化。如果配置文件被修改，Viper将触发一个事件
	v.WatchConfig()
	// 注册一个回调函数，当配置文件发生变化时会被调用。
	// 这个回调函数接收一个fsnotify.Event参数，包含有关文件变化的事件信息
	v.OnConfigChange(func(e fsnotify.Event) {
		fmt.Println("config file changed: ", e.Name)
		// 重新进行序列化
		if err = v.Unmarshal(&global.GBSS_CONFIG); err != nil {
			fmt.Println(err)
		}
	})
	// 在程序启动时，立即将配置文件的内容反序列化到global.GBSS_CONFIG变量中。
	// 如果反序列化失败，程序将输出错误消息并终止执行。
	if err = v.Unmarshal(&global.GBSS_CONFIG); err != nil {
		panic(err)
	}
	return v
}
